
# 2020/7/16
# encoding=utf-8
from dnac_f import *
import threading  # 需要开一个线程监视处理是否完成
import time  # 需要用到延迟sleep()函数
import sys

"""
功能：
    1.获取所管辖的所有网元、主机的信息，并打印出来
    2.然后用户选择某两个设备
    3.然后在控制器端创建analysis分析程序，track出Source发包到Destination所经过的所有设备
    4.并发一个线程，监视分析程序的进度，若最后完成tracking，则本地打印出结果。
    5.（预想可以做一个可视化）
"""


# -----获取所管辖的所有网元、主机的信息-----
def get_host_and_device(controller):
    ip_list = []
    idx = 0
          # 先获取host的信息
    try:
        response_json = controller.get(api="host")
        i = 0
        if response_json["response"] != []:
            for item in response_json["response"]:
                i += 1
                ip_list.append([i, "host", item["hostIp"]])
            idx = i  # This idx(sequential number) is used to tag host and network device
    except:
        print("Something went wrong. Cannot get the host IP list")

    # 再获取device的信息
    try:
        response_json = controller.get(api="network-device")
        print("Status: of GET /network-device ")
        if response_json["response"] != []:
            for item in response_json["response"]:
                idx += 1
                ip_list.append([idx, "network device", item["managementIpAddress"]])
    except:
        print("Something went wrong! Cannot get the network device IP list!")

    # 通过tabulate打印出来信息
    if len(ip_list) < 2:
        print("You need at least two hosts or network devices to perform a path trace!")
        sys.exit()
    print(tabulate(ip_list, headers=['number', 'type', 'ip'], tablefmt="rst"))
    return ip_list


# -----让用户做出选择，然后该函数返回对应的IP-----
def select_ip(prompt, ip_list, idx=2):
    ip = ""
    while True:
        user_input = input(prompt)
        user_input = user_input.lstrip()  # Ignore leading space
        if user_input.lower() == 'exit':
            sys.exit()
        if user_input.isdigit():
            if int(user_input) in range(1, len(ip_list) + 1):
                ip = ip_list[int(user_input) - 1][idx]  # The idx is the position of IP
                return ip
            else:
                print("Oops! The number you selected is out of range. Please try again or enter 'exit'")
        else:
            print("Oops! The input you entered is not a number. Please try again or enter 'exit'")


# 创建analysis应用。这不是一下子就创建好的，需要一段时间，但是会先返回应用ID号。
def create_analysis(s_ip, d_ip, controller):
    # 下面两行代码才是重点，创建flow-analysis
    path_data = {"sourceIP": s_ip, "destIP": d_ip}
    response_json = controller.post(api="flow-analysis", data=path_data, )

    try:
        flowAnalysisId = response_json["response"]["flowAnalysisId"]  # 取得flowAnalysisId
        return flowAnalysisId
    except:
        print("\n For some reason, you cannot get the flowAnalysisId")
        sys.exit()


# -----通过应用ID号来检查analysis程序的构建进度（也会打印），若构建完毕，则打印最终结果-----
def check_status(status, flowAnalysisId, cotroller):  # 监视进度
    global response
    count = 0
    #  以下是表明出问题了的话
    while status != "COMPLETED":
        if status == "FAILED":
            print(
                "Unable to find the full path. No traceroute or netflow information was found. The path calculation failed.")
            print("\n------ End of path trace ! ------")
            sys.exit()
        print("\nTask is not finished yet, sleep 1 second then try again")
        time.sleep(1)
        count += 1
        if count > 30:  # timeout after ~ 30 seconds
            print(
                "\nScript timed out. No routing path was found. Please try using a different source and destination !")
            print("\n------ End of path trace ! ------")
            sys.exit()

        try:  # 这里才使用ID API***
            response_json = cotroller.get(api="flow-analysis/" + flowAnalysisId)
            print("Response from GET /flow-analysis/" + flowAnalysisId)
            print(json.dumps(response_json, indent=4))
            # print(response_json["response"])
            response = response_json["response"]
            status = response_json["response"]["request"]["status"]
            print("\n Check status here: ", status, " \n")
        except:  # APi访问不了的话
            # Something is wrong
            print("\nSomething went wrong while running get /flow-analysis/{flowAnalysisId}")
    print("\n------ End of path trace ! ------")

if __name__ == "__main__":
    my_dnac = dnac()

    nd_list = get_host_and_device(my_dnac)

    print(" Note: Not all source/destination ip address pairs will return a path. No route!  \n")
    s_ip = select_ip('=> Select a number for the source IP from the list shown: ', nd_list)  # ip_idx (=2) is the position of IP in the list
    d_ip = select_ip('=> Select a number for the destination IP from the list shown: ', nd_list)  # ip_idx (=2) is the position of IP in the list

    flowAnalysisId = create_analysis(s_ip, d_ip, my_dnac)

    # 接下来是线程并发，因为得有一分支监视analysis是否完成。
    thread = threading.Thread(target=check_status, args=('', flowAnalysisId, my_dnac))
    thread.start()


